﻿using System;
using System.Collections.Generic;
using System.Threading;

namespace RemoteData.core.queue
{
    /// <summary>
    /// 
    /// </summary>
    /// <typeparam name="W">worker类型</typeparam>
    /// <typeparam name="E"></typeparam>
    /// <typeparam name="D"></typeparam>
    public class Dispatcher<W, E, D>
    {
        // 为保证线程安全，使用一个锁来保护msgDispatchTbl的访问
        // readonly static object _locker = new object();

        private ReaderWriterLockSlim rwLock = new ReaderWriterLockSlim();

        //消息的分发table
        private Dictionary<E, List<W>> msgDispatchTbl = new Dictionary<E, List<W>>();

        public List<W> GetWorkers(E msgType)
        {
            List<W> workers = null;

            rwLock.EnterReadLock();
            try
            {
                bool existFlag = msgDispatchTbl.ContainsKey(msgType);
                if (existFlag)
                {
                    workers = msgDispatchTbl[msgType];
                }
            }
            finally
            {
                rwLock.ExitReadLock();
            }

            return workers;
        }

        public int Register(W worker, E msgType)
        {
            int rn = 0;
            rwLock.EnterWriteLock();

            try
            {
                bool existFlag = msgDispatchTbl.ContainsKey(msgType);
                List<W> msgHandlerList = null;
                if (!existFlag)
                {
                    msgHandlerList = new List<W>();
                    msgDispatchTbl.Add(msgType, msgHandlerList);
                }
                else
                {
                    msgHandlerList = msgDispatchTbl[msgType];
                }

                msgHandlerList.Add(worker);
            }
            catch (Exception)
            {

                rn = -1;
            }
            finally
            {
                rwLock.ExitWriteLock();
            }

            return rn;
        }

        public int Register(W worker, List<E> msgTypeList)
        {
            int rn = 0;
            rwLock.EnterWriteLock();
            try
            {
                foreach (var msgType in msgTypeList)
                {
                    bool existFlag = msgDispatchTbl.ContainsKey(msgType);
                    List<W> WorkerList = null;
                    if (!existFlag)
                    {
                        WorkerList = new List<W>();
                        msgDispatchTbl.Add(msgType, WorkerList);
                    }
                    else
                    {
                        WorkerList = msgDispatchTbl[msgType];
                    }

                    //check
                    bool chkFlag = true;
                    foreach (var v in WorkerList)
                    {
                        //已经注册过
                        if (v.Equals(worker))
                        {
                            chkFlag = false;
                            break;
                        }
                    }
                    //如果没注册，注册
                    if (chkFlag)
                    {
                        WorkerList.Add(worker);
                    }




                }
            }
            catch (Exception)
            {
                rn = -1;
            }
            finally
            {
                rwLock.ExitWriteLock();
            }

            return rn;
        }

        public void UnRegister(W worker, E msgType)
        {
            rwLock.EnterWriteLock();

            try
            {
                bool existFlag = msgDispatchTbl.ContainsKey(msgType);

                if (existFlag)
                {
                    List<W> WorkerList = msgDispatchTbl[msgType];
                    WorkerList.Remove(worker);
                }
            }
            catch (Exception)
            {

            }
            finally
            {
                rwLock.ExitWriteLock();
            }

        }

        public void UnRegister(W worker, List<E> msgTypeList)
        {
            rwLock.EnterWriteLock();

            try
            {
                foreach (var msgType in msgTypeList)
                {
                    bool existFlag = msgDispatchTbl.ContainsKey(msgType);
                    if (existFlag)
                    {
                        List<W> WorkerList = msgDispatchTbl[msgType];
                        WorkerList.Remove(worker);
                    }
                }
            }
            catch
            {

            }
            finally
            {
                rwLock.ExitWriteLock();
            }

        }

        public virtual E GetDataType(D data)
        {
            return default(E);
        }

        public virtual void Notify(W worker, D data)
        {

        }

        public void NotifyAll(D data)
        {
            rwLock.EnterReadLock();
            try
            {
                //停止消息，发给所有的接收者
                if (data == null)
                {
                    ///不发送停止消息，由worker自行停止
                    //TW_App.workerPool.NotifyStopMsg();
                }
                else
                {
                    E msgType = GetDataType(data);
                    if (!msgDispatchTbl.ContainsKey(msgType)) return;

                    List<W> WorkerList = msgDispatchTbl[msgType];
                    foreach (var v in WorkerList)
                    {
                        //接收指定消息          
                        Notify(v, data);
                    }
                }
            }
            catch
            {

            }
            finally
            {
                rwLock.ExitReadLock();
            }
        }
    }
}
